﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Windows;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;

namespace Gmantis.Imaging
{
    internal class AnimationFrameCollection : List<AnimationFrame>
    {
        // Fields
        private Bitmap _bmp;
        private int _frameIndex;
        private int _loopCount;
        private Storyboard _sb;

        // Methods
        internal AnimationFrameCollection(Bitmap bmp)
        {
            this._bmp = bmp;
        }

        private void _sb_Completed(object sender, EventArgs e)
        {
            this._frameIndex++;
            if ((this._frameIndex >= base.Count) && (this.LoopCount > 0))
            {
                this.LoopCount--;
                this._frameIndex = 0;
            }
            if (this._frameIndex < base.Count)
            {
                this.ShowCurrentFrame();
            }
        }

        public void BeginAnimation()
        {
            if (((base.Count > 1) && (this.LoopCount > 0)) && (this._bmp.GetImageSource() != null))
            {
                if (this._sb == null)
                {
                    this._sb = new Storyboard();
                    this._sb.Completed += new EventHandler(this._sb_Completed);
                }
                this._sb.Stop();
                this._frameIndex = 0;
                this.ShowCurrentFrame();
            }
        }

        public void Clear()
        {
            this.Stop();
            this.LoopCount = 0;
            base.Clear();
        }

        private Stream GetFrameStream(AnimationFrame frame)
        {
            if (frame.FrameStream == null)
            {
                Bitmap bitmap = new Bitmap(frame.Width, frame.Height);
                if (this._frameIndex > 0)
                {
                    AnimationFrame frame2 = base[this._frameIndex - 1];
                    switch (frame2.FrameDisposal)
                    {
                        case FrameDisposal.Keep:
                            bitmap.DrawBitmap(frame2.FrameImage, 0, 0);
                            break;

                        case FrameDisposal.RestorePrevious:
                            if (this._frameIndex > 1)
                            {
                                frame2 = base[this._frameIndex - 2];
                                bitmap.DrawBitmap(frame2.FrameImage, 0, 0);
                            }
                            break;
                    }
                }
                bitmap.DrawBitmap(frame.Bitmap, frame.Left, frame.Top);
                frame.FrameImage = bitmap;
                frame.FrameStream = bitmap.GetStream(false);
                if (this._frameIndex == (base.Count - 1))
                {
                    foreach (AnimationFrame frame3 in this)
                    {
                        frame3.FrameImage = null;
                    }
                }
                else
                {
                    for (int i = 0; i < (this._frameIndex - 1); i++)
                    {
                        base[i].FrameImage = null;
                    }
                }
            }
            return frame.FrameStream;
        }

        public void Pause()
        {
            if (this._sb != null)
            {
                this._sb.Pause();
            }
        }

        public void Resume()
        {
            if (this._sb != null)
            {
                this._sb.Resume();
            }
        }

        private void ShowCurrentFrame()
        {
            BitmapImage imageSource = this._bmp.GetImageSource();
            AnimationFrame frame = base[this._frameIndex];
            this.GetFrameStream(frame);
            if ((frame.Bitmap.Width > 0) && (frame.Bitmap.Height > 0))
            {
                imageSource.SetSource(frame.FrameStream);
            }
            int num = (frame.Delay == 0) ? 50 : frame.Delay;
            TimeSpan timeSpan = TimeSpan.FromMilliseconds((double)num);
            this._sb.Duration = new Duration(timeSpan);
            this._sb.Begin();
        }

        public void Stop()
        {
            if (this._sb != null)
            {
                this._sb.Stop();
            }
        }

        // Properties
        public ClockState CurrentState
        {
            get
            {
                if (this._sb == null)
                {
                    return ClockState.Stopped;
                }
                return this._sb.GetCurrentState();
            }
        }

        public int LoopCount
        {
            get
            {
                return this._loopCount;
            }
            set
            {
                this._loopCount = value;
            }
        }
    }
}
